use std::{collections::HashMap, error::Error, vec, time::SystemTime};

use crate::util::{option_plus::OptionPlus};
use crate::channel::tcp::prelude::NrUReader;

/// RFC HTTP请求规范
/// 
/// Request  = Request-Line CRLF    ; Since 5.1
/// 
/// *(( 
/// 
///     general-header              ; Since 4.5
/// 
///     | request-header            ; Since 5.3
/// 
///     | entity-header             ; Since 7.1
/// 
/// ) CRLF) CRLF
/// 
///    [ message-body ]             ; Since 4.3
#[derive(Debug, Clone)]
pub struct Request {
    pub method: String,
    pub uri: String,
    pub version: String,
    pub path_param: HashMap<String, String>,
    pub header: HashMap<String, String>,
    pub body: Vec<u8>,
    pub create_time: SystemTime,
}

impl Request {
    pub fn new() -> Self {
        Self { 
            method: "".to_string(), 
            uri: "".to_string(), 
            version: "".to_string(), 
            path_param: HashMap::new(), 
            header: HashMap::new(), 
            body: vec![],
            create_time: SystemTime::now(),
        }
    }

    pub fn read_from_stream(reader: &mut NrUReader) -> Result<Self, Box<dyn Error>> {
        let mut req = Self::new();
        let mut bytes: Vec<u8> = vec![];
        loop {
            match reader.next() {
                Ok(ob) => {
                    if ob.is_some() {
                        let b = ob.unwrap();
                        bytes.push(b);
                        if b == b'\n' && endwith_sp(&bytes, super::SP) {
                            // 去掉尾部SP
                            let info_lines = bytes_to_lines(bytes[..bytes.len() - 4].to_vec());
                            req.set_req_info(OptionPlus::ok_or_other(info_lines.get(0), &"".to_string()));
                            for i in 1..info_lines.len() {
                                let s = info_lines.get(i).unwrap();
                                if s.is_empty() {
                                    break
                                } else {
                                    let (k, v) = str_to_map(s);
                                    req.header.insert(k, v);
                                }
                            }
                            break
                        }
                    }
                },
                Err(_) => return Err("Read from reader error".into()),
            }
        }

        if req.chunked() {
            let end_str = String::from("0\r\n\r\n");
            let end_bytes = end_str.as_bytes();
            loop {
                req.body.push(reader.next().unwrap().unwrap());
                if req.body.len() >= end_bytes.len() && &req.body[req.body.len() - end_bytes.len()..] == end_bytes {
                    break;
                }
            }
        } else {
            let mut content_size = 0_usize;
            match req.header.get(super::CL) {
                Some(s) => content_size = s.parse().unwrap(),
                None => {},
            }
    
            if content_size > 0 {
                let mut times = 0_usize;
                loop {
                    if times >= content_size {
                        break;
                    }
                    match reader.next().unwrap() {
                        Some(b) => {
                            req.body.push(b);
                            times = times + 1;
                        },
                        None => {},
                    }
                }
            }
        }
        Ok(req)
    }

    pub fn to_vec(&self) -> Vec<u8> {
        let mut req: String = String::from("");
        req = req + &self.method + &String::from(" ") + &self.uri + &self.param_to_string() + &String::from(" ") + &self.version + &String::from("\r\n");
        req = req + &self.header_to_lines();
        req = req + &String::from("\r\n\r\n");
        let mut vec_byte = req.as_bytes().to_vec();
        if self.body.len() > 0 {
            vec_byte.append(&mut self.body.clone());
        }
        vec_byte
    }

    fn param_to_string(&self) -> String {
        if self.path_param.len() > 0 {
            let mut param = String::from("?");
            for (k, v) in &self.path_param {
                param = param + k + &String::from("=") + v + "&";
            }
            param.remove(param.len() - 1);
            param
        } else {
            String::from("")
        }
    }

    fn header_to_lines(&self) -> String {
        if self.header.len() > 0 {
            let mut lines = String::from("");
            for (k, v) in &self.header {
                lines = lines + k + &String::from(": ") + v + &String::from("\r\n");
            }
            lines.remove(lines.len() - 1);
            lines.remove(lines.len() - 1);
            lines
        } else {
            String::from("")
        }
    }

    /// 解析HTTP请求第一行内容
    fn set_req_info(&mut self, line: &String) {
        let mut first_line_split = line.split(" ");
    
        self.method = first_line_split.next().ok_or("Unknow request method").unwrap().to_string();
    
        // request uri
        let uri_and_path_params = first_line_split.next().ok_or("URI not specified").unwrap();
        let mut uri_and_path_params_split = uri_and_path_params.split("?");
        let uri = uri_and_path_params_split.next().ok_or("URI missing").unwrap();
        self.uri = uri.to_string();
    
        // request path param
        match uri_and_path_params_split.next() {
            Option::Some(params) => {
                let mut param_iter = params.split("&");
                loop {
                    match param_iter.next() {
                        Option::Some(item) => {
                            let mut kv_iter = item.split("=");
                            self.path_param.insert(kv_iter.next().unwrap().to_string(), OptionPlus::ok_or_other(kv_iter.next(), "").to_string());
                        },
                        Option::None => { break; }
                    }
                }
            },
            Option::None => {}
        }
    
        self.version = first_line_split.next().ok_or("Unknow request method").unwrap().to_string();
    }

    pub fn keep_alive(&self) -> bool {
        self.header.get(super::CN).is_some() && "keep-alive".eq(self.header.get(super::CN).unwrap())
    }

    pub fn chunked(&self) -> bool {
        self.header.get(super::TE).is_some() && "chunked".eq(self.header.get(super::TE).unwrap())
    }

}

fn endwith_sp(haystack: &Vec<u8>, split: &[u8]) -> bool {
    haystack.len() >= split.len() && haystack[haystack.len() - split.len()..] == split[..]
}

/// 发现第一个SP下标
fn find_sp(haystack: &Vec<u8>, split: &[u8]) -> Option<usize> {
    (0..haystack.len() - split.len() + 1)
        .filter(|&i| haystack[i..i + split.len()] == split[..]).next()
}

/// 根据\r\n将bytes分为lines
fn bytes_to_lines(mut bytes: Vec<u8>) -> Vec<String> {
    let mut lines = vec![];
    loop {
        match find_sp(&bytes, super::CRLF) {
            Some(i) => {
                lines.append(&mut bytes_to_lines_splitr(&bytes[0..i].to_vec()));
                let temp = bytes[i + 2..].to_vec();
                bytes = temp;
            },
            None => {
                lines.append(&mut bytes_to_lines_splitr(&bytes[..].to_vec()));
                break
            },
        }
    }
    lines
}

/// 根据\r将bytes分为lines
fn bytes_to_lines_splitr(bytes: &Vec<u8>) -> Vec<String> {
    let mut lines = vec![];
    loop {
        match find_sp(bytes, &[b'\r']) {
            Some(i) => {
                lines.push(String::from_utf8(bytes[0..i].to_vec()).unwrap());
            },
            None => {
                lines.push(String::from_utf8(bytes[..].to_vec()).unwrap());
                break
            },
        }
    }
    lines
}

fn str_to_map(line: &String) -> (String, String) {
    let index = line.find(": ").unwrap();
    (line[0..index].to_string(), line[(index + 2)..].to_string())
}